//
//  ZoomInWithAnchorView.swift
//  NavigationAnimation
//
//  Created by hongyan.yang on 2021/9/14.
//

import UIKit

protocol TransformAnimationViewController {
    var animator: TransformAnimator { get }
    var animatingView: UIView { get }
}

extension TransformAnimationViewController {
    func animatingViewFrame() -> CGRect {
        animatingView.superview!.layoutIfNeeded() // have autolayout engine to recalculate the constraints so that we wouldn't get incorrect frame
        return self.animatingView.superview!.convert(animatingView.frame, to: self.animatingView.window)
    }
}


class TransformAnimator: NSObject, UIViewControllerAnimatedTransitioning {
    
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.3
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard
            let toVC = transitionContext.viewController(forKey: .to) as? TransformAnimationViewController,
            let fromVC = transitionContext.viewController(forKey: .from) as? TransformAnimationViewController,
            let fromView = transitionContext.view(forKey: .from),
            let toView = transitionContext.view(forKey: .to),
            let fromSnapshot = fromVC.animatingView.snapshotView(afterScreenUpdates: false) // afterScreenUpdates must be false because frame will changed
        else {
            return
        }
        
        let containerView = transitionContext.containerView
        
        toView.alpha = 0
        transitionContext.containerView.addSubview(toView)
        
        fromSnapshot.frame = fromVC.animatingViewFrame()
        
        guard let toSnapshot = toVC.animatingView.snapshotView(afterScreenUpdates: true) else { // get toSnapshot after toVC added to containerView
            return
        }
        toSnapshot.alpha = 0 // hide toSnapshot before we fade in it
        containerView.addSubview(toSnapshot)
        containerView.addSubview(fromSnapshot)
        
        let moveToRect = fromSnapshot.frame.scaleToFill(in: toVC.animatingViewFrame())
        // hide these two because we will do animation with their snapshots instead of themselves
        fromVC.animatingView.isHidden = true
        toVC.animatingView.isHidden = true
        
        let duration = transitionDuration(using: transitionContext)
        UIView.animate(withDuration: duration, animations: {
            fromView.alpha = 0 // fade out fromView
            toView.alpha = 1 // fade in toView
            fromSnapshot.alpha = 0 // fade out fromView
            toSnapshot.alpha = 1 // fade in toSnapshot
            fromSnapshot.frame = moveToRect // change fromSnapshot's frome to toSnapshot's
//            containerView.setNeedsLayout()
//            containerView.layoutIfNeeded()
        }) { (success) in
            fromVC.animatingView.isHidden = false // show fromVC's animationView after animating
            toVC.animatingView.isHidden = false // show toVC's animationView after animating
            fromSnapshot.removeFromSuperview() // remove fromSnapshot
            toSnapshot.removeFromSuperview() // remove toSnapshot
            transitionContext.completeTransition(true) // Notify UIKit tansition ending
        }
    }
}
extension TransformAnimator: UINavigationControllerDelegate {
    func navigationController(_ navigationController: UINavigationController,
                              animationControllerFor operation: UINavigationController.Operation,
                              from fromVC: UIViewController,
                              to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?
    {
        guard
            let _ = fromVC as? TransformAnimationViewController,
            let _ = toVC as? TransformAnimationViewController else {
            return nil
        }
        return self
    }
}
